home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / text / hyper / hsc_source.lha / hsc / source / hsctools / hscdepp.c < prev    next >
C/C++ Source or Header  |  1996-11-17  |  18KB  |  720 lines

  1. /*
  2.  * hscdepp
  3.  *
  4.  * hsc dependency procreator
  5.  *
  6.  * Copyright (C) 1996  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  *-------------------------------------------------------------------
  23.  *
  24.  * Author : Thomas Aglassinger (Tommy-Saftwörx)
  25.  * Email  : agi@giga.or.at, agi@sbox.tu-graz.ac.at
  26.  * Address: Lissagasse 12/II/9
  27.  *          8020 Graz
  28.  *          AUSTRIA
  29.  *
  30.  *-------------------------------------------------------------------
  31.  *
  32.  * hsctools/hscdepp.c
  33.  *
  34.  * updated: 17-Nov-1996
  35.  * created:  8-Jul-1996
  36.  */
  37.  
  38. /* ANSI includes */
  39. #include <stdio.h>
  40. #include <errno.h>
  41. #include <string.h>
  42. #include <time.h>
  43.  
  44. /* include revision data */
  45. #include "hsctools/depp_rev.h"
  46.  
  47. /* ugly includes */
  48. #include "ugly/ustring.h"
  49. #include "ugly/dllist.h"
  50. #include "ugly/expstr.h"
  51. #include "ugly/infile.h"
  52. #include "ugly/uargs.h"
  53. #include "ugly/prginfo.h"
  54. #include "ugly/returncd.h"
  55.  
  56. /* hsclib includes */
  57. #include "hscprj/document.h"
  58. #include "hscprj/project.h"
  59. #include "hscprj/license.h"
  60.  
  61. #ifdef AMIGA
  62. /* AmigaOS version string
  63.  * (imported from "hscdepp_rev.h")
  64.  */
  65. static const STRPTR AmigaOS_version = VERSTAG;
  66. #endif
  67.  
  68. /* prefix for messages */
  69. #define HD ""
  70. #define DHD "*hscdep* "
  71. #define SHIT "*** "             /* prefix for total failure */
  72.  
  73. /* debugging define */
  74. #ifdef DEBUG
  75. #undef DEBUG
  76. #define DEBUG 1
  77. #endif
  78.  
  79. #ifdef D
  80. #undef D
  81. #endif
  82.  
  83. #if DEBUG
  84. #define D(x) if (debug) {x;}
  85. #else
  86. #define D(x) {/*nufin*/}
  87. #endif
  88.  
  89. /* step-sizes for input-file/depency-string */
  90. #define CHUNKSIZE_INPUTFILE (64*1024)
  91. #define CHUNKSIZE_DEPENDSTR (16*1024)
  92.  
  93. /* default parameters */
  94. #define DEFAULT_PROJECT "hsc.project"   /* project-filename */
  95. #define DEFAULT_NAMEALL "all_hsc"       /* "all"-rule */
  96.  
  97. /* size of buffer for fgets() */
  98. #define MAXBUFSIZE 1024
  99.  
  100. #define STR_DEPENDS_PRECEDE \
  101.     "# --- DO NOT MODIFY THIS LINE -- hsc-dependencies precede ---\n"
  102. #define STR_DEPENDS_FOLLOW \
  103.     "# --- DO NOT MODIFY THIS LINE -- hsc-dependencies follow ---\n"
  104.  
  105. /*
  106.  * global vars
  107.  */
  108. static int return_code = RC_FAIL;       /* exit code of program */
  109.  
  110. static STRPTR makefile = NULL;
  111. static STRPTR prjfile = NULL;
  112. static STRPTR nameall = NULL;
  113. static BOOL verbose = FALSE;
  114. static BOOL nobackup = FALSE;
  115. static BOOL notaglines = FALSE;
  116. static BOOL debug = FALSE;
  117.  
  118. static EXPSTR *lines_precede = NULL;
  119. static EXPSTR *lines_follow = NULL;
  120. static EXPSTR *lines_depend = NULL;
  121.  
  122. static HSCPRJ *project = NULL;
  123.  
  124. /*
  125.  * cleanup: free all resources
  126.  * (called in any case)
  127.  */
  128. static VOID cleanup(VOID)
  129. {
  130.     D(fprintf(stderr, "(cleanup)\r"));
  131.     del_project(project);
  132.     del_estr(lines_precede);
  133.     del_estr(lines_follow);
  134.     del_estr(lines_depend);
  135.     D(fprintf(stderr, "         "));
  136. }
  137.  
  138. static VOID set_return_code(int new_code)
  139. {
  140.     if (new_code > return_code)
  141.         return_code = new_code;
  142. }
  143.  
  144. /*
  145.  * hsc_nomem_handler
  146.  *
  147.  * called from ugly/umalloc, if malloc() did return NULL
  148.  */
  149. static BOOL hscdepp_nomem_handler(size_t size)
  150. {
  151.     fputs(SHIT "out of memory\n", stderr);
  152.  
  153.     return_code = RC_FAIL;
  154.  
  155.     exit(return_code);
  156.  
  157.     return (FALSE);             /* immediatly abort */
  158. }
  159.  
  160. VOID msg_corrupt_pf(HSCPRJ * hp, STRPTR reason)
  161. {
  162.     fprintf(stderr, "project-file corrupt: %s\n", reason);
  163. }
  164.  
  165. /*
  166.  * args_ok
  167.  *
  168.  * prepare args, check & parse user args, display error and
  169.  * help message if neccessary
  170.  *
  171.  * result: TRUE, if all args ok and no request for HELP or
  172.  *         LICENSE has been detected
  173.  */
  174. static BOOL args_ok(int argc, char *argv[])
  175. {
  176.     struct arglist *hscdepp_args;       /* argument structure */
  177.     BOOL arg_help = FALSE;
  178.     BOOL arg_license = FALSE;
  179.     BOOL ok = FALSE;
  180.  
  181.     /* create arg-table */
  182.     hscdepp_args = prepare_args
  183.         ("HSCDEPP_ARGS",
  184.          "FILE/T", &makefile, "makefile to update",
  185.          "PRJFILE/T/K", &prjfile, "project file",
  186.          "NAMEALL/T/K", &nameall, "name for `all_hsc' rule",
  187.          "VERBOSE/S", &verbose, "verbose output",
  188.          "NOBACKUP/S", &nobackup, "do not backup makefile",
  189.          "NOTAGLINES/S", ¬aglines, "do not write taglines",
  190.          "-DEBUG/S", &debug, "enable debugging output",
  191.          "HELP=?=-h/S", &arg_help, "display this text",
  192.          "LICENSE/S", &arg_license, "display license",
  193.          NULL);
  194.  
  195.     ok = (hscdepp_args != NULL);
  196.  
  197.     /* set & test args */
  198.     if (ok)
  199.     {
  200.         ok = set_args(argc, argv, hscdepp_args);
  201.  
  202.         /* display argument error message */
  203.         if (!ok)
  204.         {
  205.             pargerr();
  206.             set_return_code(RC_ERROR);
  207.         }
  208.         else if (arg_help || arg_license)
  209.         {
  210.             /*
  211.              * display help or license text
  212.              */
  213.             fprintf_prginfo(stderr);
  214.             if (arg_help)
  215.                 fprintf_arghelp(stderr, hscdepp_args);
  216.             else
  217.                 show_license();
  218.             set_return_code(RC_WARN);
  219.             ok = FALSE;
  220.         }
  221.         else
  222.         {
  223.             /* auto-enable verbose in debug-mode */
  224.             if (debug)
  225.                 verbose = TRUE;
  226.  
  227.             /* display copyright in verbose-mode */
  228.             if (verbose)
  229.                 fprintf_prginfo(stderr);
  230.  
  231.             /* set default-parameters if neccessary */
  232.             if (!prjfile)
  233.             {
  234.                 prjfile = DEFAULT_PROJECT;
  235.                 if (verbose)
  236.                     fprintf(stderr, HD "%s: using default project-file\n",
  237.                             prjfile);
  238.             }
  239.             if (!nameall)
  240.             {
  241.                 nameall = DEFAULT_NAMEALL;
  242.  
  243.             }
  244.  
  245.             /* debugging control output */
  246.             D(
  247.                  if (makefile)
  248.                  {
  249.                  fprintf(stderr, DHD "makefile=`%s'\n", makefile);
  250.                  fprintf(stderr, DHD "makefile=DEFAULT\n");
  251.                  fprintf(stderr, DHD "prjfile =`%s'\n", prjfile);
  252.                  fprintf(stderr, DHD "nameall =`%s'\n", nameall);
  253.                  }
  254.             );
  255.         }
  256.  
  257.         /* release mem used by args */
  258.         free_args(hscdepp_args);
  259.     }
  260.     else
  261.     {
  262.         /* only for developer */
  263.         D(fprintf(stderr, SHIT "ArgDef error: %lu\n", prep_error_num));
  264.     }
  265.  
  266. #if 1
  267.     return (ok);
  268. #else
  269.     return (FALSE);             /* for arg-debugging */
  270. #endif
  271. }
  272.  
  273. /*
  274.  * read_makefile
  275.  *
  276.  * scan for fitting makefile, read all it's data into a list
  277.  * of strings, exept those which are between taglines
  278.  */
  279. static BOOL read_makefile(VOID)
  280. {
  281.     STRPTR scanfile[] =
  282.     {"GNUmakefile", "Makefile", "makefile", NULL};
  283.     FILE *file = NULL;
  284.     BOOL ok = FALSE;
  285.  
  286.     lines_precede = init_estr(1024);
  287.     lines_follow = init_estr(1024);
  288.  
  289.     /*
  290.      * open makefile
  291.      */
  292.     errno = 0;
  293.     if (!makefile)
  294.     {
  295.         /* scan for makefile */
  296.         int i = 0;
  297.  
  298.         D(fprintf(stderr, DHD "scanning makefile\n"));
  299.         makefile = scanfile[0];
  300.         while (!file && makefile)
  301.         {
  302.             D(fprintf(stderr, DHD "  try `%s'\n", makefile));
  303.             file = fopen(makefile, "r");
  304.             if (!file)
  305.             {
  306.                 i += 1;
  307.                 makefile = scanfile[i];
  308.             }
  309.         }
  310.  
  311.     }
  312.     else
  313.     {
  314.         /* use makefile specified by user */
  315.         D(fprintf(stderr, DHD "makefile `%s' specified by user\n", makefile));
  316.         file = fopen(makefile, "r");
  317.     }
  318.  
  319.     if (!file)
  320.     {
  321.         if (!makefile)
  322.             makefile = "Makefile";
  323.         fprintf(stderr, HD "%s: creating new makefile\n", makefile);
  324.         ok = TRUE;
  325.     }
  326.     else
  327.     {
  328.         static STRARR buf[MAXBUFSIZE];  /* buffer for fgets() */
  329.         BOOL found = FALSE;     /* flag: tag-line found */
  330.         STRPTR line = NULL;     /* current line read */
  331.  
  332.         /*
  333.          * read Makefile
  334.          */
  335.  
  336.         /* reset error variable */
  337.         errno = 0;
  338.  
  339.         /*
  340.          * read preceding lines
  341.          */
  342.         do
  343.         {
  344.             line = fgets(buf, MAXBUFSIZE, file);
  345.             if (line)
  346.                 if (!strcmp(line, STR_DEPENDS_FOLLOW))
  347.                     found = TRUE;
  348.                 else
  349.                     app_estr(lines_precede, line);
  350.         }
  351.         while (!found && !errno && line);
  352.  
  353.         if (errno)
  354.         {
  355.             fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  356.             set_return_code(RC_ERROR);
  357.         }
  358.         else if (!line)
  359.         {
  360.             /* tag-line not found */
  361.             if (verbose)
  362.                 fprintf(stderr, HD "%s: no starting tag-line; "
  363.                         "appending dependencies\n", makefile);
  364.         }
  365.         else
  366.         {
  367.             /*
  368.              * skip old dependencies
  369.              */
  370.             D(fprintf(stderr, DHD "starting tagline found\n"));
  371.  
  372.             found = FALSE;
  373.             do
  374.             {
  375.                 line = fgets(buf, MAXBUFSIZE, file);
  376.                 if (line)
  377.                     if (!strcmp(line, STR_DEPENDS_PRECEDE))
  378.                         found = TRUE;
  379.             }
  380.             while (!found && !errno && line);
  381.  
  382.             if (errno)
  383.             {
  384.                 fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  385.                 set_return_code(RC_ERROR);
  386.             }
  387.             else if (!line)
  388.             {
  389.                 /* tag-line not found */
  390.                 if (verbose)
  391.                     fprintf(stderr, HD "%s: no ending tag-line; "
  392.                             "appending dependencies\n", makefile);
  393.             }
  394.             else
  395.             {
  396.                 /*
  397.                  * read following lines
  398.                  */
  399.                 D(fprintf(stderr, DHD "ending tagline found\n"));
  400.                 do
  401.                 {
  402.                     line = fgets(buf, MAXBUFSIZE, file);
  403.                     if (line)
  404.                         app_estr(lines_follow, line);
  405.                 }
  406.                 while (!errno && line);
  407.  
  408.                 if (errno)
  409.                 {
  410.                     fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  411.                     set_return_code(RC_ERROR);
  412.                 }
  413.             }
  414.         }
  415.  
  416.         if (!errno)
  417.         {
  418.             if (verbose)
  419.                 fprintf(stderr, HD "%s: makefile read\n", makefile);
  420.             ok = TRUE;
  421.         }
  422.         /* close makefile */
  423.         fclose(file);
  424.     }
  425.  
  426.     return (ok);
  427. }
  428.  
  429. /*
  430.  * read_project
  431.  *
  432.  * read data from project file
  433.  */
  434. static BOOL read_project(VOID)
  435. {
  436.     BOOL ok = FALSE;
  437.     INFILE *inpf = NULL;
  438.  
  439.     if (verbose)
  440.     {
  441.         fprintf(stderr, HD "%s: reading..\r", prjfile);
  442.         fflush(stderr);
  443.     }
  444.  
  445.     /* assign message-callback for corrupt project-file */
  446.     project->CB_msg_corrupt_pf = msg_corrupt_pf;
  447.  
  448.     /* read project-file */
  449.     errno = 0;
  450.     inpf = infopen(prjfile, CHUNKSIZE_INPUTFILE);
  451.     if (inpf)
  452.     {
  453.         if (hsc_project_read_file(project, inpf))
  454.         {
  455.             if (verbose)
  456.                 fprintf(stderr, HD "%s: project-file read\n", prjfile);
  457.             ok = TRUE;
  458.         }
  459.         infclose(inpf);
  460.     }
  461.  
  462.     if (!ok)
  463.     {
  464.         fprintf(stderr, HD "error reading `%s'", prjfile);
  465.         if (errno)
  466.             fprintf(stderr, HD ": %s", strerror(errno));
  467.         fprintf(stderr, "\n");
  468.     }
  469.  
  470.     return (ok);
  471. }
  472.  
  473. /*
  474.  * update_makefile
  475.  *
  476.  * create dependency-lines from project-info,
  477.  */
  478.  
  479. /* append linefeed to dependency-line */
  480. static VOID depline_applf(ULONG * linelen)
  481. {
  482.     *linelen = 0;
  483.     app_estr(lines_depend, "\n");
  484. }
  485.  
  486. /* append string to dependency-line */
  487. static VOID depline_appstr(STRPTR s, ULONG * linelen)
  488. {
  489. #define LEADING_BLANKS "   "
  490.     size_t slen = strlen(s);
  491.  
  492.     /* check if line would become too long after appending
  493.      * the current word */
  494.     if ((*linelen + slen) >= 75)
  495.     {
  496.         D(fprintf(stderr, DHD "break line after %lu chars to avoid %lu\n",
  497.                   *linelen, *linelen + slen));
  498.  
  499.         app_estr(lines_depend, " \\\n");
  500.         app_estr(lines_depend, LEADING_BLANKS);
  501.         *linelen = strlen(LEADING_BLANKS);
  502.     }
  503.  
  504.     app_estrch(lines_depend, ' ');
  505.     app_estr(lines_depend, s);
  506.     *linelen = *linelen + slen + 1;
  507. }
  508.  
  509. /*
  510.  * update_makefile - main function
  511.  */
  512. static BOOL update_makefile(VOID)
  513. {
  514.     BOOL ok = FALSE;
  515.     ULONG linelen = 0;          /* length of current line */
  516.     DLNODE *docnode = dll_first(project->documents);
  517.     BOOL bak_ok = TRUE;
  518.  
  519.     lines_depend = init_estr(CHUNKSIZE_DEPENDSTR);
  520.  
  521.     /* append tagline */
  522.     if (!notaglines)
  523.         app_estr(lines_depend, STR_DEPENDS_FOLLOW);
  524.  
  525.     /* append some header info */
  526.     if (!notaglines)
  527.     {
  528. #define MAXTIMEBUF 40
  529.         time_t now = time(NULL);
  530.         STRARR timebuf[MAXTIMEBUF];
  531.  
  532.         if (strftime(timebuf, MAXTIMEBUF, "%A %d-%b-%Y %H:%M:%S",
  533.                      localtime(&now)))
  534.         {
  535.             app_estr(lines_depend, "\n# dependencies updated: ");
  536.             app_estr(lines_depend, timebuf);
  537.             app_estr(lines_depend, "\n\n");
  538.         }
  539.     }
  540.  
  541.     /*
  542.      * append all-rule
  543.      */
  544.     if (docnode->data)
  545.     {
  546.         app_estr(lines_depend, nameall);
  547.         app_estr(lines_depend, " :");
  548.         linelen = strlen(nameall) + 2;
  549.  
  550.         while (docnode)
  551.         {
  552.             HSCDOC *document = dln_data(docnode);
  553.             depline_appstr(document->docname, &linelen);
  554.  
  555.             docnode = dln_next(docnode);
  556.         }
  557.         app_estr(lines_depend, "\n\n");
  558.     }
  559.  
  560.     /*
  561.      * append document data
  562.      */
  563.     docnode = dll_first(project->documents);
  564.     while (docnode)
  565.     {
  566.         HSCDOC *document = dln_data(docnode);
  567.         DLNODE *incnode = dll_first(document->includes);
  568.  
  569.         D(fprintf(stderr, DHD "document `%s'\n", document->docname));
  570.  
  571.         app_estr(lines_depend, document->docname);
  572.         app_estr(lines_depend, " :");
  573.  
  574.         linelen = strlen(document->docname) + 2;
  575.  
  576.         /* dependency for main source */
  577.         depline_appstr(document->sourcename, &linelen);
  578.  
  579.         /* dependencies for includes */
  580.         while (incnode)
  581.         {
  582.             HSCINC *include = dln_data(incnode);
  583.             depline_appstr(include->name, &linelen);
  584.  
  585.             incnode = dln_next(incnode);
  586.         }
  587.  
  588.         /* append linefeed after dependency-list */
  589.         app_estr(lines_depend, "\n\n");
  590.  
  591.         docnode = dln_next(docnode);
  592.     }
  593.  
  594.     /* append tagline */
  595.     if (!notaglines)
  596.         app_estr(lines_depend, STR_DEPENDS_PRECEDE);
  597.  
  598.     /*
  599.      * create backup
  600.      */
  601.     if (!nobackup)
  602.     {
  603.         EXPSTR *makefile_bak = init_estr(32);   /* filename for backup */
  604.  
  605.         set_estr(makefile_bak, makefile);
  606.         app_estr(makefile_bak, ".bak");
  607.  
  608.         /* remove old backup */
  609.         remove(estr2str(makefile_bak));
  610.  
  611.         /* rename old makefile to backup
  612.          *
  613.          * NOTE: if this fails, this can also be because
  614.          * there wasn't any earlier copy, therefor no
  615.          * error-message is displayed */
  616.         if (!rename(makefile, estr2str(makefile_bak)))
  617.         {
  618.             if (verbose)
  619.                 fprintf(stderr, HD "%s: backup created\n",
  620.                         estr2str(makefile_bak));
  621.         }
  622.  
  623.         del_estr(makefile_bak);
  624.     }
  625.  
  626.     /*
  627.      * write makefile
  628.      */
  629.     if (bak_ok)
  630.     {
  631.         FILE *outf = NULL;
  632.  
  633.         /* open output makefile */
  634.         errno = 0;
  635.         outf = fopen(makefile, "w");
  636.         if (outf)
  637.         {
  638.             /* write output */
  639.             errno = 0;
  640.             fprintf(outf, "%s%s%s",
  641.                     estr2str(lines_precede), estr2str(lines_depend),
  642.                     estr2str(lines_follow));
  643.  
  644.             if (errno)
  645.             {
  646.                 /* write error */
  647.                 fprintf(stderr, "error writing to `%s': %s\n",
  648.                         makefile, strerror(errno));
  649.             }
  650.             else
  651.                 ok = TRUE;
  652.  
  653.             /* close output */
  654.             fclose(outf);
  655.         }
  656.         else
  657.         {
  658.             /* error opening output */
  659.             fprintf(stderr, "error opening `%s' for output: %s\n",
  660.                     makefile, strerror(errno));
  661.         }
  662.     }
  663.  
  664.     return (ok);
  665. }
  666.  
  667. /*
  668.  *
  669.  * main function
  670.  *
  671.  */
  672. int main(int argc, char *argv[])
  673. {
  674. #ifndef BETA
  675. #define BETA 0
  676. #endif
  677.     /* set program information */
  678.     set_prginfo("hscdepp", "Tommy-Saftwörx", VERSION, REVISION, BETA,
  679.                 "hsc dependency procreator",
  680.                 "Freeware, type `hscdepp LICENSE' for details.");
  681.  
  682. #if DEBUG
  683.     /* display a memory tracking report */
  684.     /* at end of execution */
  685.     atexit(atexit_uglymemory);
  686. #endif
  687.  
  688.     /* install nomem-handler */
  689.     ugly_nomem_handler = hscdepp_nomem_handler;
  690.  
  691.     /* use cleanup() as additional exit func */
  692.     if (!atexit(cleanup))
  693.     {
  694.         /*
  695.          * main procedure
  696.          */
  697.         return_code = RC_OK;
  698.         project = new_project();
  699.         if (project
  700.             && args_ok(argc, argv)
  701.             && read_makefile()
  702.             && read_project()
  703.             && update_makefile()
  704.         )
  705.         {
  706.             if (verbose)
  707.             {
  708.                 fprintf(stderr, HD "%s: updated using `%s'\n",
  709.                         makefile, prjfile);
  710.             }
  711.             return_code = RC_OK;
  712.         }
  713.     }
  714.     else
  715.     {
  716.         fputs(SHIT "atexit() failed ", stderr);
  717.     }
  718.     return (return_code);
  719. }
  720.